package com.neusoft.databus.agent.interactive.collect;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;

import com.neusoft.bizcore.common.utils.DateUtil;
import com.neusoft.bizcore.web.utils.JsonUtils;
import com.neusoft.bizcore.web.utils.SpringUtil;
import com.neusoft.databus.agent.config.MenjinPluginProperties;
import com.neusoft.databus.agent.pool.menjin.MenjinConnector;
import com.neusoft.databus.agent.utils.RSAUtils;
import com.neusoft.databus.common.bean.CommandBean;
import com.neusoft.databus.common.bean.MetricBean;
import com.neusoft.databus.common.connection.MenjinConnection;
import com.neusoft.databus.common.exception.ConfigErrorException;
import com.neusoft.databus.common.interactive.collect.Collector;
import com.neusoft.databus.common.parser.Parser;

import lombok.extern.slf4j.Slf4j;

/**
 * description
 *
 * @author sunchf
 * @date 2019年4月2日 上午9:37:26
 */
@Slf4j
public class MenjinMenjinCollector extends Collector<CloseableHttpClient> {

    private final MenjinPluginProperties properties;

    public MenjinMenjinCollector(final Parser parser) {
        super(parser);
        this.connector = SpringUtil.getBean(MenjinConnector.class);
        this.properties = SpringUtil.getBean(MenjinPluginProperties.class);
    }

    @Override
    protected void doCollect(final CommandBean command) throws Exception {

        if (command.getResourceBean().size() != 1) {
            throw new ConfigErrorException("不支持批量采集");
        }

        final List<MetricBean> metrics = command.getResourceBean().get(0).getMetrics();
        if (metrics.size() == 0) {
            throw new ConfigErrorException("门禁采集需要配置data指标");
        }

        if (metrics.stream().filter(it -> "data".equals(it.getVariable())).count() == 0) {
            final MetricBean bean = new MetricBean();
            bean.setCode("data");
            bean.setName("门禁记录");
            bean.setVariable("data");
            metrics.add(bean);
        }

        try {
            this.conn = this.connector.getConn(command.getConnection().asUsedConnection());
            this.sendCommand(command, ((MenjinConnection) command.getConnection()).getLoginName(),
                    ((MenjinConnection) command.getConnection()).getLoginPass());

        } catch (final Exception e) {
            throw e;
        } finally {
            try {
                if (MenjinMenjinCollector.log.isDebugEnabled()) {
                    MenjinMenjinCollector.log.debug("return connection object to poll, {}", command.getConnection());
                }
                this.connector.returnConn(command.getConnection().asUsedConnection(), this.conn);
            } catch (final Exception e) {

            }
        }

    }

    public void sendCommand(final CommandBean command, final String loginName, final String loginPass)
            throws Exception {

        final String baseUrl = "http://" + ((MenjinConnection) command.getConnection()).getHost() + ":"
                + ((MenjinConnection) command.getConnection()).getPort();

        int days = ((MenjinConnection) command.getConnection()).getDays();
        days = days < 1 ? 1 : days;
        int pageSize = ((MenjinConnection) command.getConnection()).getPageSize();
        pageSize = pageSize < 1 ? 200 : pageSize;

        final String publicKey = this.getPublicKey(baseUrl, loginName);
        final String[] userToken = this.getToken(baseUrl, loginName, loginPass, publicKey);
        final String userId = userToken[0];
        final String token = userToken[1];

        final String channelCode = (String) command.getResourceBean().get(0).getConfig().get("channelCode");
        if (StringUtils.isBlank(channelCode)) {
            throw new ConfigErrorException("门禁采集需要指标组配置channelCode参数");
        }
        final String jsonStr = this.getCardRecord(baseUrl, loginName, userId, token, channelCode, days, pageSize);
        command.getResourceBean().get(0).getMetrics().forEach(it -> {
            it.setOriginalValue(jsonStr);
            it.setValue(jsonStr);
        });

    }

    private String getPublicKey(final String baseUrl, final String loginName) throws Exception {

        final URIBuilder uriBuilder = this.buildUrl(baseUrl, this.properties.getPublicKeyUri());
        final HttpPost httppost = new HttpPost(uriBuilder.build());
        httppost.setHeader("Content-Type", "application/json");

        final Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("loginName", loginName);

        httppost.setEntity(new StringEntity(JsonUtils.pojoToJson(paramMap), Charset.forName("UTF-8")));

        CloseableHttpResponse response = null;
        try {
            response = this.conn.execute(httppost, HttpClientContext.create());
            final HttpEntity entity = response.getEntity();
            final String result = EntityUtils.toString(entity, "utf-8");
            MenjinMenjinCollector.log.info("getPublicKey: {}", result);
            EntityUtils.consume(entity);
            final Map<String, Object> mapRes = JsonUtils.jsonToMap(result);
            if (!mapRes.containsKey("publicKey")) {
                throw new ConfigErrorException("无法获取公钥");
            }
            return (String) mapRes.get("publicKey");
        } catch (final Exception e) {
            throw e;
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (final IOException e) {
            }
        }
    }

    private String[] getToken(final String baseUrl, final String loginName, final String loginPass,
            final String publicKey) throws Exception {
        final URIBuilder uriBuilder = this.buildUrl(baseUrl, this.properties.getTokenUri());

        final HttpPost httppost = new HttpPost(uriBuilder.build());
        httppost.setHeader("Content-Type", "application/json");

        final Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("loginName", loginName);
        paramMap.put("loginPass", RSAUtils.encryptBASE64(RSAUtils.encryptByPublicKey(loginPass.getBytes(), publicKey)));

        httppost.setEntity(new StringEntity(JsonUtils.pojoToJson(paramMap), Charset.forName("UTF-8")));

        //        final List<NameValuePair> nvps = new ArrayList<>();
        //        nvps.add(new BasicNameValuePair("loginName", loginName));
        //        nvps.add(new BasicNameValuePair("loginPass",
        //                RSAUtils.encryptBASE64(RSAUtils.encryptByPublicKey(loginPass.getBytes(), publicKey))));
        //        try {
        //            httppost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
        //        } catch (final UnsupportedEncodingException e) {
        //            throw e;
        //        }

        CloseableHttpResponse response = null;
        try {
            response = this.conn.execute(httppost,
                    HttpClientContext.create());
            final HttpEntity entity = response.getEntity();
            final String result = EntityUtils.toString(entity, "utf-8");
            MenjinMenjinCollector.log.info("getToken: {}", result);
            EntityUtils.consume(entity);
            final Map<String, Object> mapRes = JsonUtils.jsonToMap(result);

            if (!mapRes.containsKey("token")) {
                throw new ConfigErrorException("无法获取token");
            }
            if (!mapRes.containsKey("id")) {
                throw new ConfigErrorException("无法获取用户ID");
            }

            return new String[] {(String) mapRes.get("id"), (String) mapRes.get("token") };
        } catch (final Exception e) {
            throw e;
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (final IOException e) {
            }
        }
    }

    private String getCardRecord(final String baseUrl, final String loginName, final String userId, final String token,
            final String channelCode, final int days, final int pageSize) throws Exception {

        final URIBuilder uriBuilder =
                this.buildUrl(baseUrl, this.properties.getCardRecordUri(), userId, loginName, token);
        final HttpPost httppost = new HttpPost(uriBuilder.build());
        httppost.setHeader("Content-Type", "application/json");

        final Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("pageNum", "1");
        paramMap.put("pageSize", pageSize);
        paramMap.put("channelCode", channelCode);
        final Date now = new Date();
        final Date startOfToday = DateUtil.getStartTimeOfDate(now);
        final long timeOfBeforeDays = startOfToday.getTime() - (days * 86400000);

        paramMap.put("endSwingTime", DateUtil.date2String(now, "yyyy-MM-dd HH:mm:ss"));
        paramMap.put("startSwingTime", DateUtil.date2String(new Date(timeOfBeforeDays), "yyyy-MM-dd HH:mm:ss"));

        httppost.setEntity(new StringEntity(JsonUtils.pojoToJson(paramMap), Charset.forName("UTF-8")));

        //        final List<NameValuePair> nvps = new ArrayList<>();
        //        nvps.add(new BasicNameValuePair("pageNum", "1"));
        //        nvps.add(new BasicNameValuePair("pageSize", "10000"));
        //        nvps.add(new BasicNameValuePair("channelCode", channelCode));
        //
        //        final Date now = new Date();
        //        nvps.add(new BasicNameValuePair("startSwingTime", DateUtil.date2String(now, "yyyy-MM-dd HH:mm:ss")));
        //        nvps.add(new BasicNameValuePair("endSwingTime",
        //                DateUtil.date2String(DateUtil.getEndTimeOfDate(now), "yyyy-MM-dd HH:mm:ss")));
        //        try {
        //            httppost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
        //        } catch (final UnsupportedEncodingException e) {
        //            throw e;
        //        }

        CloseableHttpResponse response = null;
        try {
            response = this.conn.execute(httppost, HttpClientContext.create());
            final HttpEntity entity = response.getEntity();
            final String result = EntityUtils.toString(entity, "utf-8");
            MenjinMenjinCollector.log.info("getCardRecord: {}", result);
            EntityUtils.consume(entity);
            return result;
        } catch (final Exception e) {
            throw e;
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (final IOException e) {
            }
        }
    }

    private URIBuilder buildUrl(final String baseUrl, final String uri, final Object... params)
            throws URISyntaxException {
        final StringBuilder sb = new StringBuilder();
        sb.append(baseUrl);
        sb.append(uri);

        return new URIBuilder(String.format(sb.toString(), params));
    }

}
